#include "cgmmap.h"
#include <sys/mman.h>

/*
 * Ukaze na pozadovany blok mapovaneho souboru
 */
void
cgm_read_fs_block(GLBVAL *glb, void **buf, off_t offset)
{
	off_t cgoff;
	
	cgoff = (off_t) cgstart(&afs, (glb->acg)->cg_cgx);
	cgoff = (off_t) fsbtodb(&afs, cgoff);
	cgoff *= DEV_BSIZE;
	
	offset = fsbtodb(&afs, offset);		/* fs blk disk blk */
	offset *= DEV_BSIZE;				/* disk blk to bytes */
	
	offset -= cgoff;
	
	*buf = &(((char *)(glb->memcg))[offset]);	
}

/*
 * Prekopiruje buffer do mapovany oblasti.
 */
int
cgm_write_fs_block(GLBVAL *glb, char *src, off_t offset)
{
	char *dest;
	off_t cgoff;
	

	cgoff = (off_t) cgstart(&afs, (glb->acg)->cg_cgx);
	cgoff = (off_t) fsbtodb(&afs, cgoff);
	cgoff *= DEV_BSIZE;
	
	offset = fsbtodb(&afs, offset);		/* fs blk disk blk */
	offset *= DEV_BSIZE;				/* disk blk to bytes */
	offset -= cgoff;
	
	dest = &(((char *)(glb->memcg))[offset]);
		
	/* 
	 * Pokud jiz src ukazuje do namapovany oblasti, tak neni treba kopirovat. 
	 * Napr. oblast inodu ci ib blok.
	 */

	if (dest != src)
		if (memcpy(dest, src, afs.fs_bsize) != dest)
			return 1;

	return 0;
}

int
cgm_unmap(GLBVAL *glb)
{
	size_t	cgsize;

	msync(glb->memcg, 0, MS_SYNC);
	cgsize = ((glb->acg)->cg_ndblk / afs.fs_frag)*afs.fs_bsize;
	if (munmap(glb->memcg, cgsize) < 0) {
		perror("Unmapping cg error");
		return 1;
	}
	
	return 0;
}

/*
 * Projde cely mapovany prostor a tim jej nacte do pameti.
 * Pokud se nenacte a udela se pwrite na usek, ktery jeste
 * neni v pameti, tak EFAULT.. - chyba nejspis v OBSD, 
 * v linux jde ok.
 * 
 * Ve vysledku lepsi, jelikoz pruchod cyklem je urcite rychlejsi nez samotne
 * cteni. Az dojde ke skutecnemu cteni z disku, tak jiz bude ve fronte cekat
 * nekolik pozadavku, takze velka sance ze budu cist po velkych usecich bez 
 * zbytecnych presunu cteci hlavy.
 */
void
pre_read (GLBVAL *glb, size_t cgsize)
{
	int i;
	int incr;
	char a;
	
	/* to zajisti minimalne jeden pristup do bloku */
	incr = afs.fs_fsize;
	
	for (i = 1; i < cgsize; i+= incr)
		a = ((char *)(glb->memcg))[i];
		
}

/*
 * Mapovani celeho cg do pameti.
 */
int
cgmmap(GLBVAL *glb, int cgx)
{
	size_t 	cgsize;
	off_t 	cgoff;
	void 	*memcg;
	cgun 	aacg;
	
	struct cg *acg_loc = (struct cg *) &(aacg.cg);	
	
	/* 
	 * poprve potrebuju nacisti cg pres tuto fci ... 
	 * potrebuji jiz nyni cg_nbblk
	 */
	if (read_cgblock_ft (glb, &acg_loc, cgx))
		return 1;

	cgsize = (acg_loc->cg_ndblk / afs.fs_frag);
	cgsize = cgsize * afs.fs_bsize;
	cgoff = (off_t) cgstart(&afs, cgx);
	cgoff = (off_t) fsbtodb(&afs, cgoff);
	cgoff *= DEV_BSIZE;

	memcg = mmap (NULL, cgsize, PROT_READ | PROT_WRITE, MAP_FILE|MAP_SHARED, glb->fd, cgoff);
	if (memcg == MAP_FAILED) {
		perror("Can not mapped cg into memory");
		return 1;
	}

	glb->memcg = memcg;
	glb->flags |= GLBCGISMMAP;
	
	pre_read(glb, cgsize);

	return 0;
}
